package com.eastfair.certificate.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.eastfair.annotation.annotation.base.BaseControllerInfo;
import com.eastfair.annotation.annotation.log.SysLog;
import com.eastfair.annotation.annotation.security.PreAuth;
import com.eastfair.auth.dto.RoleDTO;
import com.eastfair.cache.projectcore.DictionaryCacheKeyBuilder;
import com.eastfair.cache.repository.CachePlusOps;
import com.eastfair.certificate.dto.*;
import com.eastfair.certificate.entity.Certificate;
import com.eastfair.certificate.entity.CertificateIndex;
import com.eastfair.certificate.enumeration.CertificateIndexClassifyEnum;
import com.eastfair.certificate.exceptioncode.CertificateExceptionCode;
import com.eastfair.certificate.service.CertificateIndexService;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.eastfair.boot.controller.SuperController;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.eastfair.certificate.service.CertificateService;
import com.eastfair.certificate.vo.CertificateIndexLeadVO;
import com.eastfair.certificate.vo.CertificateIndexVO;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.model.CacheHashKey;
import com.eastfair.demand.certificate.CertificateOrderGroup;
import com.eastfair.echo.core.EchoService;
import com.eastfair.core.base.R;
import com.eastfair.projectcore.api.DictionaryFeign;
import com.eastfair.projectcore.entity.Dictionary;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.eastfair.boot.request.PageParams;
import com.eastfair.core.context.ContextUtil;

import static com.eastfair.core.base.R.SUCCESS_CODE;


/**
 * <p>
 * 前端控制器
 * 证件指标设置
 * </p>
 *
 * @author ligang
 * @date 2022-07-21
 */
@Slf4j
@Validated
@RestController
@RequestMapping("/certificateIndex")
@Api(value = "CertificateIndex", tags = "证件指标设置")
@PreAuth(replace = "certificate:certificateIndex:")
public class CertificateIndexController extends SuperController<CertificateIndexService, Long, CertificateIndex, CertificateIndexPageQuery, CertificateIndexSaveDTO, CertificateIndexUpdateDTO> {

    @Autowired
    private EchoService echoService;

    @Autowired
    CertificateService certificateService;
    @Autowired
    private CachePlusOps cachePlusOps;

    @Autowired
    DictionaryFeign dictionaryFeign;

    @Override
    public void handlerResult(IPage<CertificateIndex> page) {
        // 想让返回值实现自动回显，请将此行代码打开
        // echoService.action(page);
    }

    /**
     * Excel导入后的操作
     *
     * @param list
     */
    @Override
    public R<Boolean> handlerImport(List<Map<String, String>> list) {
        List<CertificateIndex> certificateIndexList = list.stream().map((map) -> {
            CertificateIndex certificateIndex = CertificateIndex.builder().build();
            //TODO 请在这里完成转换
            return certificateIndex;
        }).collect(Collectors.toList());

        return R.success(baseService.saveBatch(certificateIndexList));
    }


    /**
     * 处理参数
     *
     * @param params 分页参数
     */
    @Override
    public void handlerQueryParams(PageParams<CertificateIndexPageQuery> params) {
        CertificateIndexPageQuery pageQuery = params.getModel();
        //分页处理
        if (ContextUtil.getProjectId() != null) {
            pageQuery.setProjectId(ContextUtil.getProjectId());
        }
    }

    /**
     * 创建证件指标
     *
     * @param certificateIndexDTO 证件指标实体
     * @return
     */
    @ApiOperation(value = "创建证件指标", notes = "创建证件指标")
    @PostMapping("/create")
    @SysLog("创建证件指标")
    public R create(@RequestBody CertificateIndexDTO certificateIndexDTO) {
        R r = verifyCertificateindex(certificateIndexDTO);
        if (SUCCESS_CODE != r.getCode()) {
            return r;
        }
        if (verifyTime(certificateIndexDTO)) {
            throw BizException.wrap(CertificateExceptionCode.INDEX_TIME_NO);
        }
        CertificateIndex certificateIndex = new CertificateIndex();
        BeanUtils.copyProperties(certificateIndexDTO, certificateIndex);
        baseService.save(certificateIndex);
        return R.success(certificateIndex);
    }

    /**
     * 校验时间重叠
     *
     * @param certificateIndexDTO
     * @return
     */
    public Boolean verifyTime(CertificateIndexDTO certificateIndexDTO) {
        CertificateIndexDTO certificateIndexDTO2 = new CertificateIndexDTO();
        certificateIndexDTO2.setCertificateId(certificateIndexDTO.getCertificateId());
        certificateIndexDTO2.setClassify(certificateIndexDTO.getClassify());
        certificateIndexDTO2.setSpaceCode(certificateIndexDTO.getSpaceCode());
        certificateIndexDTO2.setExhibitionId(certificateIndexDTO.getExhibitionId());
        List<CertificateIndex> certificateIndexList = baseService.list(certificateIndexDTO2, null);
        if (certificateIndexList == null || certificateIndexList.isEmpty()) {
            return false;
        }
        //剔除自身id
        certificateIndexList = certificateIndexList.stream().filter(s -> !s.getId().equals(certificateIndexDTO.getId())).collect(Collectors.toList());
        for (CertificateIndex certificateIndex : certificateIndexList) {
            if (hasOverlap(certificateIndex.getStartTime(), certificateIndex.getEndTime(), certificateIndexDTO.getStartTime(), certificateIndexDTO.getEndTime())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 思路：将有交集的情况列出,若不符合有交集的情况,则无交集
     * 有交集的两种情况
     * 1.第一个时间段的开始时间在第二个时间段的开始时间和结束时间当中
     * 2.第二个时间段的开始时间在第一个时间段的开始时间和结束时间当中
     * 判断两个时间段是否有交集
     *
     * @param leftStartDate  第一个时间段的开始时间
     * @param leftEndDate    第一个时间段的结束时间
     * @param rightStartDate 第二个时间段的开始时间
     * @param rightEndDate   第二个时间段的结束时间
     * @return 若有交集, 返回true, 否则返回false
     */
    public boolean hasOverlap(LocalDateTime leftStartDate, LocalDateTime leftEndDate, LocalDateTime rightStartDate, LocalDateTime rightEndDate) {

        log.info("时间对比: startdate1:{},endDate1:{}, startdate2:{},endDate2:{}", leftStartDate, leftEndDate, rightStartDate, rightEndDate);
        Boolean isHasOver = true;
        if (leftStartDate.isAfter(rightEndDate)) {
            //开始时间 大于 对比的结束时间
            isHasOver = false;
        } else if (leftStartDate.isBefore(rightStartDate) && leftEndDate.isBefore(rightStartDate)) {
            //开始时间 小于 对比的开始时间  并且 结束时间 小于 对比的开始时间
            isHasOver = false;
        }

        log.info("时间对比reuslt: {}", isHasOver);

        return isHasOver;
//        return ((Timestamp.valueOf(leftStartDate).getTime() >= Timestamp.valueOf(rightStartDate).getTime())
//                && Timestamp.valueOf(leftStartDate).getTime() < Timestamp.valueOf(rightEndDate).getTime())
//                ||
//                ((Timestamp.valueOf(leftStartDate).getTime() > Timestamp.valueOf(rightStartDate).getTime())
//                        && Timestamp.valueOf(leftStartDate).getTime() <= Timestamp.valueOf(rightEndDate).getTime())
//                ||
//                ((Timestamp.valueOf(rightStartDate).getTime() >= Timestamp.valueOf(leftStartDate).getTime())
//                        && Timestamp.valueOf(rightStartDate).getTime() < Timestamp.valueOf(leftEndDate).getTime())
//                ||
//                ((Timestamp.valueOf(rightStartDate).getTime() > Timestamp.valueOf(leftStartDate).getTime())
//                        && Timestamp.valueOf(rightStartDate).getTime() <= Timestamp.valueOf(leftEndDate).getTime());


    }

    /**
     * 证件指标分页
     *
     * @param params 证件指标实体
     * @return
     */
    @ApiOperation(value = "证件指标分页", notes = "证件指标分页")
    @PostMapping("/pageVo")
    public R<IPage<CertificateIndexVO>> pageVo(@RequestBody PageParams<CertificateIndexDTO> params) {
        IPage<CertificateIndexVO> page = baseService.pageVo(params);
        return R.success(page);
    }

    /**
     * 更新证件指标
     *
     * @param certificateIndexDTO 证件指标实体
     * @return
     */
    @ApiOperation(value = "更新证件指标", notes = "更新证件指标")
    @PutMapping("/update")
    @SysLog("更新证件指标")
    public R update(@RequestBody @Validated({RoleDTO.createRole.class}) CertificateIndexDTO certificateIndexDTO) {
        R r = verifyCertificateindex(certificateIndexDTO);
        if (SUCCESS_CODE != r.getCode()) {
            return r;
        }
        if (verifyTime(certificateIndexDTO)) {
            throw BizException.wrap(CertificateExceptionCode.INDEX_TIME_NO);
        }
        CertificateIndex certificateIndex = new CertificateIndex();
        BeanUtils.copyProperties(certificateIndexDTO, certificateIndex);
        baseService.updateById(certificateIndex);
        return R.success(certificateIndex);
    }


    /**
     * 查询证件指标
     *
     * @param certificateId 证件ID
     * @return
     */
    @ApiOperation(value = "查询证件指标", notes = "查询证件指标")
    @GetMapping("/queryList")
    public R<List<CertificateIndexVO>> queryList(Long certificateId) {
        CertificateIndexDTO certificateIndexDTO = new CertificateIndexDTO();
        certificateIndexDTO.setCertificateId(certificateId);
        return R.success(baseService.doToVos(baseService.list(certificateIndexDTO, null)));
    }

    /**
     * 查询证件指标 前端用
     *
     * @param certificateId 证件ID
     * @param classify
     * @param spaceCode
     * @param fieldType     返回类型 classify，spaceCode，startTime
     * @return
     */
    @ApiOperation(value = "查询证件指标", notes = "查询证件指标")
    @GetMapping("/queryListOfLead")
    @SysLog("查询证件指标")
    @BaseControllerInfo(voGroup = CertificateOrderGroup.queryListOfLead.class)
    public R<List<Map>> queryListOfLead(Long certificateId, CertificateIndexClassifyEnum classify, String spaceCode, String fieldType) {
        List<Map> mapList = new ArrayList<>();
        CertificateIndexDTO certificateIndexDTO = new CertificateIndexDTO();
        certificateIndexDTO.setCertificateId(certificateId);
        certificateIndexDTO.setClassify(classify);
        certificateIndexDTO.setSpaceCode(spaceCode);
        List<CertificateIndexVO> certificateIndexVOList = baseService.doToVos(baseService.list(certificateIndexDTO, null));
        List<CertificateIndexLeadVO> result = new ArrayList<>();
        if (certificateIndexVOList != null && !certificateIndexVOList.isEmpty()) {
            for (CertificateIndexVO certificateIndexVO : certificateIndexVOList) {
                CertificateIndexLeadVO certificateIndexLeadVO = new CertificateIndexLeadVO();
                BeanUtils.copyProperties(certificateIndexVO, certificateIndexLeadVO);
                certificateIndexLeadVO.setId(certificateIndexVO.getId());
                //解析字典
                String type = "CERTIFICATE_INDEX_CLASSIFY";
                CacheHashKey typeKey = new DictionaryCacheKeyBuilder().hashFieldKey(type, Dictionary.class.getName());
                List<Dictionary> objectList = cachePlusOps.hGet(typeKey);
                if (objectList == null || objectList.isEmpty()) {
                    R<List<Dictionary>> listR = dictionaryFeign.queryDict(type);
                    if (listR.getIsSuccess()) {
                        objectList = listR.getData();
                    }
                }
                for (Dictionary dictionary1 : objectList) {
                    if (dictionary1.getCode().equals(certificateIndexLeadVO.getClassify().getCode())) {
                        certificateIndexLeadVO.setClassifyStr(dictionary1.getName());
                    }
                }
                result.add(certificateIndexLeadVO);
            }


            //去重
            if ("classify".equals(fieldType)) {
                for (CertificateIndexLeadVO certificateIndexLeadVO : result) {
                    Map map = new HashMap();
                    map.put("classify", certificateIndexLeadVO.getClassify().getCode());
                    map.put("classifyStr", certificateIndexLeadVO.getClassifyStr());
                    if (CollectionUtil.isEmpty(mapList.stream().filter(s -> certificateIndexLeadVO.getClassify().getCode().equals(s.get("classify"))).collect(Collectors.toList()))) {
                        mapList.add(map);
                    }

                }
            } else if ("spaceCode".equals(fieldType)) {
                for (CertificateIndexLeadVO certificateIndexLeadVO : result) {
                    Map map = new HashMap();
                    map.put("spaceCode", certificateIndexLeadVO.getSpaceCode());
                    if (CollectionUtil.isEmpty(mapList.stream().filter(s -> certificateIndexLeadVO.getSpaceCode().equals(s.get("spaceCode"))).collect(Collectors.toList()))) {
                        mapList.add(map);
                    }
                }
            } else if ("startTime".equals(fieldType)) {
                for (CertificateIndexLeadVO certificateIndexLeadVO : result) {
                    Map map = new HashMap();
                    map.put("startTime", certificateIndexLeadVO.getStartTime());
                    map.put("endTime", certificateIndexLeadVO.getEndTime());
                    if (CollectionUtil.isEmpty(mapList.stream().filter(s -> certificateIndexLeadVO.getStartTime().equals(s.get("startTime"))).collect(Collectors.toList()))) {
                        mapList.add(map);
                    }
                }
            }
        }
        return R.success(mapList);
    }

    /**
     * 校验证件指标
     *
     * @return
     */
    public R verifyCertificateindex(CertificateIndexDTO certificateIndexDTO) {
        List<Certificate> certificateList = certificateService.list(null, Arrays.asList(certificateIndexDTO.getCertificateId()));
        if (certificateList == null || certificateList.isEmpty()) {
            return R.fail("没有证件信息");
        }
        Certificate certificate = certificateList.get(0);
        /**
         * 指标数
         */
        Integer indexNumber = certificate.getIndexNumber();
        CertificateIndexDTO queryCertificateIndexDTO = new CertificateIndexDTO();
        queryCertificateIndexDTO.setCertificateId(certificate.getId());
        List<CertificateIndex> certificateIndexList = baseService.list(queryCertificateIndexDTO, null);
        if (certificateIndexList != null && !certificateIndexList.isEmpty()) {
            //剔除自身id
            certificateIndexList = certificateIndexList.stream().filter(s -> !s.getId().equals(certificateIndexDTO.getId())).collect(Collectors.toList());
            //判断时间是否冲突
            List<CertificateIndex> filerCertificateIndexList = certificateIndexList.stream().filter(s ->
                    (s.getStartTime().isAfter(certificateIndexDTO.getStartTime()) && s.getEndTime().isBefore(certificateIndexDTO.getStartTime()))
                            || (s.getStartTime().isAfter(certificateIndexDTO.getEndTime()) && s.getEndTime().isBefore(certificateIndexDTO.getEndTime()))
            ).collect(Collectors.toList());
            if (filerCertificateIndexList != null && !filerCertificateIndexList.isEmpty()) {
                return R.fail("指标时间冲突");
            }
            //子集指标数求和
            int conditionNumber = certificateIndexList.stream().mapToInt(CertificateIndex::getConditionNumber).sum();
            if (conditionNumber + certificateIndexDTO.getConditionNumber().intValue() > indexNumber.intValue()) {
                return R.fail("超过证件指标数");
            }
        } else {
            if (certificateIndexDTO.getConditionNumber().intValue() > indexNumber.intValue()) {
                return R.fail("超过证件指标数");
            }
        }
        return R.success();
    }
}
